import re
from jinja2 import Template
from utils.extract_data_handler import extract_by_regex
from hotloads.debugtalk import DebugTalk, faker_obj


def rend_template_str(t_str, *args, **kwargs):
    """
       渲染模板字符串, 改写了默认的引用变量语法{{var}}, 换成${var}
            模板中引用变量语法 ${var},
            调用函数 ${fun()}
            先去原内容用正则查找满足条件的${xxx()}或者${xxx}
            ${xxx()}表示热加载的函数， ${xxx}表示参数化的值
            因为每行内容可能会获取到多个${}，此时返回的是列表，如果只有一个则是字符，需要转成list
            遍历list，判断匹配到的每个item是否包含(，包含表示热加载，需要调DebugTalk定义的工具函数，
                     否则直接返回参数化的值kwargs，表示从参数化的键获取相关的参数值
        :return: 渲染之后的值
    """
    t = Template(t_str, variable_start_string='${', variable_end_string='}')
    pattern = r"\${(.*?)}"
    extract_data = extract_by_regex(t_str, pattern)
    data = None
    if extract_data:
        try:
            if not isinstance(extract_data, list):
                extract_data = [extract_data]
            for item in extract_data:
                if "(" in item:
                    content = item.split("(")
                    func_name = content[0]
                    func_vars = content[1].replace(")", "")
                    if func_name.startswith("faker"):
                        func_name = func_name.replace("faker", "")
                        func = getattr(faker_obj, func_name)
                        if not func_vars:
                            ret_data = func()
                        else:
                            ret_data = func(func_vars)
                    else:
                        func = getattr(DebugTalk(), func_name)
                        if not func_vars:
                            ret_data = func()
                        else:
                            ret_data = func(func_vars)
                    t_str = re.sub(pattern=re.compile(pattern), repl=ret_data, string=t_str, count=1)
                    data = t_str
                else:
                    data = kwargs.get(item, '')
            return data
        except Exception:  # noqa
            res = t.render(*args, **kwargs)
            return res
    else:
        res = t.render(*args, **kwargs)
        return res


def rend_template_obj(t_obj: dict, *args, **kwargs):
    """
       传 dict 对象，通过模板字符串递归查找模板字符串，转行成新的数据
    """
    if isinstance(t_obj, dict):
        for key, value in t_obj.items():
            if isinstance(value, str):
                t_obj[key] = rend_template_str(value, *args, **kwargs)
            elif isinstance(value, dict):
                rend_template_obj(value, *args, **kwargs)
            elif isinstance(value, list):
                t_obj[key] = rend_template_array(value, *args, **kwargs)
            else:
                pass
    return t_obj


def rend_template_array(t_array, *args, **kwargs):
    """
       传 list 对象，通过模板字符串递归查找模板字符串
    """
    if isinstance(t_array, list):
        new_array = []
        for item in t_array:
            if isinstance(item, str):
                new_array.append(rend_template_str(item, *args, **kwargs))
            elif isinstance(item, list):
                new_array.append(rend_template_array(item, *args, **kwargs))
            elif isinstance(item, dict):
                new_array.append(rend_template_obj(item, *args, **kwargs))
            else:
                new_array.append(item)
        return new_array
    else:
        return t_array


def rend_template_any(any_obj, *args, **kwargs):
    """渲染模板对象:str, dict, list"""
    if isinstance(any_obj, str):
        return rend_template_str(any_obj, *args, **kwargs)
    elif isinstance(any_obj, dict):
        return rend_template_obj(any_obj, *args, **kwargs)
    elif isinstance(any_obj, list):
        return rend_template_array(any_obj, *args, **kwargs)
    else:
        return any_obj
